#include "stdafx.h"
#include "CppUnitTest.h"
#include <HSModel/CreateHill.h>
#include "HSModel/SharedConstants.h"

using namespace Microsoft::VisualStudio::CppUnitTestFramework;
namespace HSModelTests
  {

  TEST_CLASS(CreateHillTest)
    {
    public:
      TEST_METHOD(GaussTest)
        {
        bool flag = true;
        size_t i0 = 5;
        size_t j0 = 5;
        double change = 10;
        for (size_t i = i0 - 1; i > 0; --i)
          {
          double first_value = HeightMapUtils::CalculateHeightChangeWithGaussDistribution(i, j0, i0, j0, change);
          double second_value = HeightMapUtils::CalculateHeightChangeWithGaussDistribution(i+1, j0, i0, j0, change);
          Assert::IsTrue (first_value <= second_value);        
          }
        }

      TEST_METHOD(HillCreationTest)
        {
        size_t SizeX = 4;
        size_t SizeY = 3;
        HeightMap HeightMap0(SizeX, SizeY);
        size_t x0 = 1;
        size_t y0 = 2;

        HeightMapUtils::CreateHill(HeightMap0, x0, y0, 1, D_UP);
        for(size_t i = 0; i < SizeX; ++i)
          {
          for(size_t j = 0; j < SizeY; j++)
            Assert::IsTrue (HeightMap0.Get(i, j) <= HeightMap0.Get(x0, y0));
          }
        for(size_t i = x0 + 1; i < SizeX; ++i)
          {
          Assert::IsTrue (HeightMap0.Get(i, y0) <= HeightMap0.Get(i - 1, y0));
          }
        }

      TEST_METHOD(HoleCreationTest)
        {
        size_t SizeX = 6;
        size_t SizeY = 4;
        HeightMap HeightMap0(SizeX, SizeY);
        size_t x0 = 2;
        size_t y0 = 2;

        HeightMapUtils::CreateHill(HeightMap0, x0, y0, 0.5, D_DOWN);
        for(size_t i = 0; i < SizeX; ++i)
          {
          for(size_t j = 0; j < SizeY; j++)
            Assert::IsTrue(HeightMap0.Get(i, j) >= HeightMap0.Get(x0, y0));
          }

        for(size_t i = x0 + 1; i < SizeX; ++i)
          {
          Assert::IsTrue(HeightMap0.Get(i, y0) >= HeightMap0.Get(i - 1, y0));     
          }
        }

      TEST_METHOD(DirectionEqualZeroTest)
        {
        size_t SizeX = 10;
        size_t SizeY = 20;
        HeightMap HeightMap0(SizeX, SizeY);
        size_t x0 = 4;
        size_t y0 = 8;
        double value = 60;
        for(size_t i=0; i < SizeX;++i)
          {
          for(size_t j = 0; j < SizeY; j++)
            HeightMap0.Set(i, j, value);
          }

        HeightMapUtils::CreateHill(HeightMap0, x0, y0, 10, D_NONE);
        for(size_t i = 0; i < SizeX; ++i)
          {
          for(size_t j = 0; j < SizeY; j++)
            Assert::AreEqual(HeightMap0.Get(i, j), value);
          }        
        }

      TEST_METHOD(HillsDoNotExceedMaxHeightValue)
        {
        // Arrange
        auto hm1 = HeightMap(8, 8);
        hm1.Set(1, 2, GroundConstants::MAX_HILL_HEIGHT / GroundConstants::CELL_SIZE - 0.6);
        hm1.Set(1, 3, GroundConstants::MAX_HILL_HEIGHT / GroundConstants::CELL_SIZE - 0.5);
        hm1.Set(2, 2, GroundConstants::MAX_HILL_HEIGHT / GroundConstants::CELL_SIZE - 0.4);
        hm1.Set(2, 3, GroundConstants::MAX_HILL_HEIGHT / GroundConstants::CELL_SIZE - 0.3);

        auto hm1_expected = GroundConstants::MAX_HILL_HEIGHT / GroundConstants::CELL_SIZE - 0.6 + GroundConstants::HMAP_CHANGE;
        
        // Act
        HeightMapUtils::CreateHill(hm1, 1, 2, GroundConstants::HMAP_CHANGE, D_UP);
        
        auto hm1_actual = hm1.Get(1, 2);
        
        // Assert
        Assert::AreEqual(hm1_expected, hm1_actual);
        }

      TEST_METHOD(HolesDoNotExceedMaxDepthValue)
        {
        // Arrange
        auto hm1 = HeightMap(8, 8);
        hm1.Set(1, 2, GroundConstants::MAX_HOLE_DEPTH / GroundConstants::CELL_SIZE + 0.6);
        hm1.Set(1, 3, GroundConstants::MAX_HOLE_DEPTH / GroundConstants::CELL_SIZE + 0.5);
        hm1.Set(2, 2, GroundConstants::MAX_HOLE_DEPTH / GroundConstants::CELL_SIZE + 0.4);
        hm1.Set(2, 3, GroundConstants::MAX_HOLE_DEPTH / GroundConstants::CELL_SIZE + 0.3);

        auto hm1_expected = GroundConstants::MAX_HOLE_DEPTH / GroundConstants::CELL_SIZE + 0.6 - GroundConstants::HMAP_CHANGE;
        
        // Act
        HeightMapUtils::CreateHill(hm1, 1, 2, GroundConstants::HMAP_CHANGE, D_DOWN);
        
        auto hm1_actual = hm1.Get(1, 2);
        
        // Assert
        Assert::AreEqual(hm1_expected, hm1_actual);
        }

      TEST_METHOD(GettingChangedByHillPoints)
        {
        // Arrange
        HeightMap map(5,5);
        map.Set(0,0,1);
        map.Set(0,1,1);
        map.Set(0,2,1);
        map.Set(0,3,1);
        map.Set(0,4,1);

        map.Set(1,0,1);
        map.Set(1,1,1);
        map.Set(1,2,1);
        map.Set(1,3,1);
        map.Set(1,4,1);

        map.Set(2,0,1);
        map.Set(2,1,1);
        map.Set(2,2,1);
        map.Set(2,3,1);
        map.Set(2,4,1);

        map.Set(3,0,1);
        map.Set(3,1,1);
        map.Set(3,2,1);
        map.Set(3,3,1);
        map.Set(3,4,1);

        map.Set(4,0,1);
        map.Set(4,1,1);
        map.Set(4,2,1);
        map.Set(4,3,1);
        map.Set(4,4,1);

        size_t base_x = 2, base_y = 2;

        std::vector<TVector3> changed;
        std::vector<std::vector<bool>> visited;
        visited.reserve(map.GetSizeX());
        for(size_t i = 0; i < map.GetSizeX(); ++i)
          {
          std::vector<bool> tmp(map.GetSizeY(), false);
          visited.push_back(tmp);
          }

        //Act
        HeightMapUtils::GetPointsThatWillBeChanged(changed, map, base_x, base_y, base_x, base_y, D_UP, GroundConstants::HMAP_CHANGE, visited);
        
        size_t size = changed.size();
        //Assert
        Assert::AreEqual(static_cast<size_t>(21), size);
        }

      TEST_METHOD(GettingChangedByHillTriangles)
        {
        // Arrange
        HeightMap map(5,5);
        map.Set(0,0,1);
        map.Set(0,1,1);
        map.Set(0,2,1);
        map.Set(0,3,1);
        map.Set(0,4,1);

        map.Set(1,0,1);
        map.Set(1,1,1);
        map.Set(1,2,1);
        map.Set(1,3,1);
        map.Set(1,4,1);

        map.Set(2,0,1);
        map.Set(2,1,1);
        map.Set(2,2,1);
        map.Set(2,3,1);
        map.Set(2,4,1);

        map.Set(3,0,1);
        map.Set(3,1,1);
        map.Set(3,2,1);
        map.Set(3,3,1);
        map.Set(3,4,1);

        map.Set(4,0,1);
        map.Set(4,1,1);
        map.Set(4,2,1);
        map.Set(4,3,1);
        map.Set(4,4,1);

        size_t base_x = 0, base_y = 0;
        Model3D model;

        //Act
        HeightMapUtils::GetTrianglesThatWillBeChanged(model, map, TVector2(base_x * 10, base_y * 10), GroundConstants::HMAP_CHANGE, D_UP);
        
        size_t count = 0;
        for(auto it = model.Triangles().begin(); it != model.Triangles().end(); ++it)
          count++;

        //Assert
        Assert::AreEqual(static_cast<size_t>(14), count);
        }

      TEST_METHOD(PointsOnEdgeTest)
        {
        // Arrange
        HeightMap map(5,5);
        map.Set(0,0,1);
        map.Set(0,1,1);
        map.Set(0,2,1);
        map.Set(0,3,1);
        map.Set(0,4,1);

        map.Set(1,0,1);
        map.Set(1,1,1);
        map.Set(1,2,1);
        map.Set(1,3,1);
        map.Set(1,4,1);

        map.Set(2,0,1);
        map.Set(2,1,1);
        map.Set(2,2,1);
        map.Set(2,3,1);
        map.Set(2,4,1);

        map.Set(3,0,1);
        map.Set(3,1,1);
        map.Set(3,2,1);
        map.Set(3,3,1);
        map.Set(3,4,1);

        map.Set(4,0,1);
        map.Set(4,1,1);
        map.Set(4,2,1);
        map.Set(4,3,1);
        map.Set(4,4,1);

        size_t base_x = 4, base_y = 4;
        Model3D model;

        //Act
        HeightMapUtils::GetTrianglesThatWillBeChanged(model, map, TVector2(base_x * 10, base_y * 10), GroundConstants::HMAP_CHANGE, D_UP);
        
        size_t count = 0;
        for(auto it = model.Triangles().begin(); it != model.Triangles().end(); ++it)
          count++;

        //Assert
        Assert::AreEqual(static_cast<size_t>(14), count);
        }
    };
  }